package notes.java.concurrent;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * 
 *  -测试常用的arraylist、Set、Hashmap它们都是线程不安全的 
 *   Collections.synchronizedXXX使得它们变成线程安全 
 *   -运行的结果都是5000
 */
public class T7_TestArrayList_Set_HashMap2 {

	// 现在要模拟一个并发程序，有5000个请求，并发量是200

	// 请求数
	private static int clientReqNum = 5000;
	// 并发数
	private static int threadSize = 200;
	
	private static List<Integer> list = Collections.synchronizedList(new ArrayList<>());
	private static Set<Integer> set = Collections.synchronizedSet(new HashSet<>());
	private static Map<Integer, Integer> map = Collections.synchronizedMap(new HashMap<>());
	
	// 操作
	private static void todo(int i) {
		list.add(i); // 每次添加一个值
		set.add(i); // 每次添加一个值
		map.put(i, i); //  每次添加一个值
	}

	public static void main(String[] args) throws Exception {
		// 创建一个线程池
		ExecutorService excutorService = Executors.newCachedThreadPool();

		// 定义一个5000大小的计数器
		CountDownLatch countDownLatch = new CountDownLatch(clientReqNum);
		// 定义一个并发200的信号量
		Semaphore semaphore = new Semaphore(threadSize);

		// 启5000个线程
		for (int i = 0; i < clientReqNum; i++) {
			int count = i;
			excutorService.execute(() -> {
				try {
					semaphore.acquire(); // 是否在200个并发量内，是就可以执行，不是就抛弃
					todo(count); // 调用执行方法
					semaphore.release();// 释放
					countDownLatch.countDown(); // 每运行一个线程后减1
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			});
		}

		// 等待所有线程运行完
		countDownLatch.await();
		// 关闭线程池
		excutorService.shutdown();
		
		System.out.println("list size:" + list.size()); // 如果是线程安全就输出5000
		System.out.println("set size:" + set.size());// 如果是线程安全就输出5000
		System.out.println("map size:" + map.size());// 如果是线程安全就输出5000
	}
}
